package com.base.game.physics;

import com.base.engine.graphics.Vertex3f;
import com.base.engine.system.EDirection;
import com.base.engine.system.ID_3D;
import com.base.game.entity.Camera;
import com.base.game.terrain.Chunk;
import com.base.game.terrain.Terrain;

public class Physics {
	
	private final Terrain terrain ; 
	
	public Physics(Terrain t){
		this.terrain = t ; 
	}

	private Chunk getChunk(Vertex3f pos){
		return this.terrain.getChunkByID(this.terrain.getCenterChunkID(pos));
	}
	
	private ID_3D getBlockID(Vertex3f pos){
		return this.terrain.getBlockPositionInChunk(pos);
	}
	
	private Vertex3f getPositionInChunk(Vertex3f pos){
		return this.terrain.getPositionInChunk(pos); 
	}

	public void fall(Camera camera) {
		camera.move(EDirection.DOWN, 0.5f); 
	}

	private ID_3D calcNorthernBlockID(ID_3D id){
		return new ID_3D(id.getX()+1, id.getY(), id.getZ()); 
	}
	private ID_3D calcSouthernBlockID(ID_3D id){
		return new ID_3D(id.getX()-1, id.getY(), id.getZ()); 
	}
	private ID_3D calcWesternBlockID(ID_3D id){
		return new ID_3D(id.getX(), id.getY(), id.getZ()-1); 
	}
	private ID_3D calcEasternBlockID(ID_3D id){
		return new ID_3D(id.getX(), id.getY(), id.getZ()+1); 
	}
	private ID_3D calcUpperBlockID(ID_3D id){
		return new ID_3D(id.getX(), id.getY()+1, id.getZ()); 
	}
	private ID_3D calcLowerBlockID(ID_3D id){
		return new ID_3D(id.getX(), id.getY()-1, id.getZ()); 
	}
	
	
	public boolean isColliding(Camera cam, Vertex3f movementVector){
		boolean res = false ; 
		Chunk chunk = this.getChunk(cam.getPos()); 
		ID_3D blockID = this.getBlockID(cam.getPos()); 
		Vertex3f camPos = this.getPositionInChunk(cam.getPos()); 
		
		camPos = Vertex3f.addVectors(camPos, movementVector); 
		
		BoundingBox[] bbPool = this.getBBsFromSurroundingBlocks(blockID); 
		
		res = 	bbPool[0].isVecInside(camPos)  // Block north
				|| bbPool[1].isVecInside(camPos) // block south
				|| bbPool[2].isVecInside(camPos) // block west 
				|| bbPool[3].isVecInside(camPos) // block east 
				|| bbPool[4].isVecInside(camPos) // block below 
//				|| bbPool[5].isVecInside(camPos) // block above // not being checked yet 
				; 
		
//		return res ; 
		return false ; 
	}

	private BoundingBox[] getBBsFromSurroundingBlocks(ID_3D blockID){
		return new BoundingBox[]{
			this.calcNorthernBB(blockID),
			this.calcSouthernBB(blockID),
			this.calcWesternBB(blockID),
			this.calcEasternBB(blockID),
			this.calcUpperBB(blockID),
			this.calcLowerBB(blockID)
		}; 
	}
	
	private BoundingBox calcNorthernBB(ID_3D blockID){
		return this.calcBBForBlock(this.calcNorthernBlockID(blockID)); 
	}
	private BoundingBox calcSouthernBB(ID_3D blockID){
		return this.calcBBForBlock(this.calcSouthernBlockID(blockID)); 
	}
	private BoundingBox calcWesternBB(ID_3D blockID){
		return this.calcBBForBlock(this.calcWesternBlockID(blockID)); 
	}
	private BoundingBox calcEasternBB(ID_3D blockID){
		return this.calcBBForBlock(this.calcEasternBlockID(blockID)); 
	}
	private BoundingBox calcUpperBB(ID_3D blockID){
		return this.calcBBForBlock(this.calcUpperBlockID(blockID)); 
	}
	private BoundingBox calcLowerBB(ID_3D blockID){
		return this.calcBBForBlock(this.calcLowerBlockID(blockID)); 
	}

	private BoundingBox calcBBForBlock(ID_3D blockID){
		float minX = blockID.getX()*Chunk.VOXEL_SIZE ; 
		float minY = blockID.getY()*Chunk.VOXEL_SIZE; 
		float minZ = blockID.getY()*Chunk.VOXEL_SIZE; 
		return new BoundingBox(minX, minY, minZ, Chunk.VOXEL_SIZE, Chunk.VOXEL_SIZE, Chunk.VOXEL_SIZE); 
	}
	
}
